﻿using Library.Collections.Generic;
using System.Linq.Expressions;

namespace Library.Linq.Expressions
{
    public sealed class ParameterReplacementVisitor : ExpressionVisitor
    {
        public ParameterReplacementVisitor(IVectorReadOnly<ParameterExpression> from, IVectorReadOnly<ParameterExpression> to)
        {
            if (from.Count != to.Count) throw new System.ArgumentException();

            this.n = from.Count;
            this.from = from;
            this.to = to;
        }

        ulong n;
        IVectorReadOnly<ParameterExpression> from;
        IVectorReadOnly<ParameterExpression> to;

        public sealed override Expression Visit(Expression node)
        {
            for (ulong x = 0; x < n; ++x)
            {
                if (from[x] == node) return to[x];
            }
            return base.Visit(node);
        }

        protected sealed override Expression VisitLambda<T>(System.Linq.Expressions.Expression<T> node)
        {
            List<ParameterExpression> parameters = new List<ParameterExpression>();
            foreach (var item in node.Parameters)
            {
                ParameterExpression parameter = VisitParameter(item) as ParameterExpression;
                parameters.Add(parameter);
            }
            System.Linq.Expressions.LambdaExpression lambda = Expression.Lambda(Visit(node.Body), node.Name, node.TailCall, parameters);
            return lambda;
        }
        protected sealed override Expression VisitParameter(ParameterExpression node)
        {
            for (ulong x = 0; x < n; ++x)
            {
                if (from[x] == node) return to[x];
            }
            return node;
        }
    }
}